home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectDraw / OverlayAnimate / overlayanimate.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  28.1 KB  |  787 lines

  1. //-----------------------------------------------------------------------------
  2. // File: OverlayAnimate.cpp
  3. //
  4. // Desc: This sample demonstrates how to animate using DirectDraw overlays
  5. //
  6. // Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <windows.h>
  10. #include <ddraw.h>
  11. #include <mmsystem.h>
  12. #include "resource.h"
  13. #include "ddutil.h"
  14. #include "dxutil.h"
  15.  
  16.  
  17.  
  18.  
  19. //-----------------------------------------------------------------------------
  20. // Defines, constants, and global variables
  21. //-----------------------------------------------------------------------------
  22. #define WINDOW_WIDTH        128
  23. #define WINDOW_HEIGHT       128
  24. #define SPRITE_DIAMETER     48
  25. #define NUM_FRAMES          30
  26.  
  27.  
  28. LPDIRECTDRAW7        g_pDD                = NULL;    
  29. LPDIRECTDRAWSURFACE7 g_pDDSPrimary        = NULL;  
  30. LPDIRECTDRAWSURFACE7 g_pDDSOverlay        = NULL;  
  31. LPDIRECTDRAWSURFACE7 g_pDDSOverlayBack    = NULL;
  32. LPDIRECTDRAWSURFACE7 g_pDDSAnimationSheet = NULL;  
  33. DDOVERLAYFX          g_OverlayFX;         
  34. DWORD                g_dwOverlayFlags     = 0;  
  35. DWORD                g_dwFrame            = 0;
  36. DDCAPS               g_ddcaps;
  37. BOOL                 g_bActive            = FALSE; 
  38. RECT                 g_rcSrc              = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
  39. RECT                 g_rcDst              = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
  40. DWORD                g_dwXRatio;
  41. DWORD                g_dwYRatio; 
  42.  
  43. // This will be used as the color key, so try to make it something
  44. // that doesn't appear in the source image.
  45. COLORREF             g_dwBackgroundColor  = RGB(10, 0, 10);
  46.  
  47.  
  48.  
  49. //-----------------------------------------------------------------------------
  50. // Function-prototypes
  51. //-----------------------------------------------------------------------------
  52. LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
  53. HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel );
  54. HRESULT InitDirectDraw( HWND hWnd );
  55. BOOL    HasOverlaySupport();
  56. VOID    FreeDirectDraw();
  57. HRESULT CreateDirectDrawSurfaces( HWND hWnd );
  58. VOID    AdjustSizeForHardwareLimits();
  59. HRESULT ProcessNextFrame( HWND hWnd );
  60. HRESULT DisplayFrame();
  61. HRESULT RestoreSurfaces();
  62.  
  63.  
  64.  
  65.  
  66. //-----------------------------------------------------------------------------
  67. // Name: WinMain()
  68. // Desc: Entry point to the program. Initializes everything and calls
  69. //       UpdateFrame() when idle from the message pump.
  70. //-----------------------------------------------------------------------------
  71. int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow )
  72. {
  73.     HRESULT  hr;
  74.     MSG         msg;
  75.     HWND     hWnd;
  76.     HACCEL   hAccel;
  77.  
  78.     if( FAILED( WinInit( hInst, nCmdShow, &hWnd, &hAccel ) ) )
  79.         return FALSE;
  80.  
  81.     if( FAILED( InitDirectDraw( hWnd ) ) )
  82.     {
  83.         MessageBox( hWnd, TEXT("DirectDraw init failed. ")
  84.                     TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
  85.                     MB_ICONERROR | MB_OK );
  86.         return FALSE;
  87.     }
  88.  
  89.     if( HasOverlaySupport() == FALSE )
  90.     {
  91.         MessageBox( hWnd, TEXT("This DirectDraw device does not support overlays. ")
  92.                     TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
  93.                     MB_ICONERROR | MB_OK );
  94.         return FALSE;
  95.     }
  96.  
  97.     // Create the DirectDraw surfaces needed
  98.     if( FAILED( hr = CreateDirectDrawSurfaces( hWnd ) ) )
  99.     {
  100.         MessageBox( hWnd, TEXT("Failed to create surfaces.  This DirectDraw device may not support overlays. ")
  101.                     TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
  102.                     MB_ICONERROR | MB_OK );
  103.         return FALSE;
  104.     }
  105.  
  106.     ShowWindow( hWnd, SW_SHOW );
  107.  
  108.     while( TRUE )
  109.     {
  110.         // Look for messages, if none are found then 
  111.         // update the state and display it
  112.         if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  113.         {
  114.             if( 0 == GetMessage(&msg, NULL, 0, 0 ) )
  115.             {
  116.                 // WM_QUIT was posted, so exit
  117.                 return (int)msg.wParam;
  118.             }
  119.  
  120.             // Translate and dispatch the message
  121.             if( 0 == TranslateAccelerator( hWnd, hAccel, &msg ) )
  122.             {
  123.                 TranslateMessage( &msg ); 
  124.                 DispatchMessage( &msg );
  125.             }
  126.         }
  127.         else
  128.         {
  129.             if( g_bActive )
  130.             {
  131.                 // Move the sprites, blt them to the back buffer, then 
  132.                 // flip or blt the back buffer to the primary buffer
  133.                 if( FAILED( ProcessNextFrame( hWnd ) ) )
  134.                 {
  135.                     g_pDD->SetCooperativeLevel( NULL, DDSCL_NORMAL );
  136.  
  137.                     MessageBox( hWnd, TEXT("Displaying the next frame failed. ")
  138.                                 TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
  139.                                 MB_ICONERROR | MB_OK );
  140.                     return FALSE;
  141.                 }
  142.             }
  143.             else
  144.             {
  145.                 // Make sure we go to sleep if we have nothing else to do
  146.                 WaitMessage();
  147.             }
  148.         }
  149.     }
  150. }
  151.  
  152.  
  153.  
  154.  
  155. //-----------------------------------------------------------------------------
  156. // Name: WinInit()
  157. // Desc: Init the window
  158. //-----------------------------------------------------------------------------
  159. HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel )
  160. {
  161.     WNDCLASSEX wc;
  162.     HWND       hWnd;
  163.     HACCEL     hAccel;
  164.  
  165.     // If we are in 8 bit mode, then we need to choose a system palette
  166.     // color because most colors will be dithered expect ones in the palette
  167.     HDC hDC = GetDC( NULL ); 
  168.     if( GetDeviceCaps( hDC, NUMCOLORS ) != -1 ) 
  169.         g_dwBackgroundColor = RGB( 255, 0, 255 );    
  170.     ReleaseDC( NULL, hDC );
  171.     
  172.     // Register the Window Class
  173.     wc.cbSize        = sizeof(wc);
  174.     wc.lpszClassName = TEXT("OverlayAnimate");
  175.     wc.lpfnWndProc   = MainWndProc;
  176.     wc.style         = CS_VREDRAW | CS_HREDRAW;
  177.     wc.hInstance     = hInst;
  178.     wc.hIcon         = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN) );
  179.     wc.hIconSm       = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN) );
  180.     wc.hCursor       = LoadCursor( NULL, IDC_ARROW );
  181.     
  182.     // Let windows paint the colorkey'ed background which our overlay will use
  183.     wc.hbrBackground = CreateSolidBrush( g_dwBackgroundColor ); 
  184.     wc.lpszMenuName  = MAKEINTRESOURCE(IDR_MENU);
  185.     wc.cbClsExtra    = 0;
  186.     wc.cbWndExtra    = 0;
  187.  
  188.     if( RegisterClassEx( &wc ) == 0 )
  189.         return E_FAIL;
  190.  
  191.     // Load keyboard accelerators
  192.     hAccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
  193.  
  194.     // Calculate the proper size for the window given a client of 640x480
  195.     DWORD dwFrameWidth    = GetSystemMetrics( SM_CXSIZEFRAME );
  196.     DWORD dwFrameHeight   = GetSystemMetrics( SM_CYSIZEFRAME );
  197.     DWORD dwMenuHeight    = GetSystemMetrics( SM_CYMENU );
  198.     DWORD dwCaptionHeight = GetSystemMetrics( SM_CYCAPTION );
  199.     DWORD dwWindowWidth   = WINDOW_WIDTH  + dwFrameWidth * 2;
  200.     DWORD dwWindowHeight  = WINDOW_HEIGHT + dwFrameHeight * 2 + 
  201.                             dwMenuHeight + dwCaptionHeight;
  202.  
  203.     // Create and show the main window
  204.     hWnd = CreateWindow( TEXT("OverlayAnimate"), TEXT("DirectDraw OverlayAnimate Sample"),
  205.                          WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
  206.                            dwWindowWidth, dwWindowHeight, NULL, NULL, hInst, NULL );
  207.     if( hWnd == NULL )
  208.         return E_FAIL;
  209.  
  210.     *phWnd   = hWnd;
  211.     *phAccel = hAccel;
  212.  
  213.     return S_OK;
  214. }
  215.  
  216.  
  217.  
  218.  
  219. //-----------------------------------------------------------------------------
  220. // Name: InitDirectDraw()
  221. // Desc: Create the DirectDraw object, and init the surfaces
  222. //-----------------------------------------------------------------------------
  223. HRESULT InitDirectDraw( HWND hWnd )
  224. {
  225.     DDSURFACEDESC2 ddsd;
  226.     HRESULT    hr;
  227.  
  228.     // Create the main DirectDraw object
  229.     if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&g_pDD, 
  230.                                          IID_IDirectDraw7, NULL ) ) )
  231.         return hr;
  232.  
  233.     // Request normal cooperative level to put us in windowed mode
  234.     if( FAILED( hr = g_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL ) ) ) 
  235.         return hr;
  236.  
  237.     // Get driver capabilities to determine Overlay support.
  238.     ZeroMemory( &g_ddcaps, sizeof(g_ddcaps) );
  239.     g_ddcaps.dwSize = sizeof(g_ddcaps);
  240.  
  241.     if( FAILED( hr = g_pDD->GetCaps( &g_ddcaps, NULL ) ) )
  242.         return hr;
  243.  
  244.     // Create the primary surface, which in windowed mode is the desktop.
  245.     ZeroMemory(&ddsd,sizeof(ddsd));
  246.     ddsd.dwSize         = sizeof(ddsd);
  247.     ddsd.dwFlags        = DDSD_CAPS;
  248.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  249.     if( FAILED( hr = g_pDD->CreateSurface( &ddsd, &g_pDDSPrimary, NULL ) ) )
  250.         return hr;
  251.         
  252.     return S_OK;
  253. }
  254.  
  255.  
  256.  
  257.  
  258. //-----------------------------------------------------------------------------
  259. // Name: CreateDirectDrawSurfaces()
  260. // Desc: Creates the DirectDraw surfaces
  261. //-----------------------------------------------------------------------------
  262. HRESULT CreateDirectDrawSurfaces( HWND hWnd )
  263. {
  264.     DDSURFACEDESC2 ddsd;
  265.     DDPIXELFORMAT  ddpfOverlayFormat;
  266.     DDSCAPS2       ddscaps;
  267.     HRESULT           hr;
  268.     
  269.     // Release any previous surfaces
  270.     SAFE_RELEASE( g_pDDSOverlay ); 
  271.  
  272.     // Set the overlay format to 16 bit RGB 5:6:5
  273.     ZeroMemory( &ddpfOverlayFormat, sizeof(ddpfOverlayFormat) );
  274.     ddpfOverlayFormat.dwSize        = sizeof(ddpfOverlayFormat);
  275.     ddpfOverlayFormat.dwFlags       = DDPF_RGB;
  276.     ddpfOverlayFormat.dwRGBBitCount = 16;
  277.     ddpfOverlayFormat.dwRBitMask    = 0xF800; 
  278.     ddpfOverlayFormat.dwGBitMask    = 0x07E0;
  279.     ddpfOverlayFormat.dwBBitMask    = 0x001F; 
  280.  
  281.     // Setup the overlay surface's attributes in the surface descriptor
  282.     ZeroMemory( &ddsd, sizeof(ddsd) );
  283.     ddsd.dwSize            = sizeof(ddsd);
  284.     ddsd.dwFlags           = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | 
  285.                              DDSD_BACKBUFFERCOUNT | DDSD_PIXELFORMAT;
  286.     ddsd.ddsCaps.dwCaps    = DDSCAPS_OVERLAY | DDSCAPS_FLIP | 
  287.                              DDSCAPS_COMPLEX | DDSCAPS_VIDEOMEMORY;
  288.     ddsd.dwBackBufferCount = 1;
  289.     ddsd.dwWidth           = WINDOW_WIDTH;
  290.     ddsd.dwHeight          = WINDOW_HEIGHT;
  291.     ddsd.ddpfPixelFormat   = ddpfOverlayFormat;  // Use 16 bit RGB 5:6:5 pixel format
  292.  
  293.     // Attempt to create the surface with theses settings
  294.     if( FAILED( hr = g_pDD->CreateSurface( &ddsd, &g_pDDSOverlay, NULL ) ) ) 
  295.         return hr;
  296.  
  297.     ZeroMemory(&ddscaps, sizeof(ddscaps));
  298.     ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  299.     if( FAILED( hr = g_pDDSOverlay->GetAttachedSurface( &ddscaps, &g_pDDSOverlayBack ) ) )
  300.         return hr;
  301.  
  302.     // Setup effects structure
  303.     ZeroMemory( &g_OverlayFX, sizeof(g_OverlayFX) );
  304.     g_OverlayFX.dwSize = sizeof(g_OverlayFX);
  305.  
  306.     // Setup overlay flags.
  307.     g_dwOverlayFlags = DDOVER_SHOW;
  308.  
  309.     // Check for destination color keying capability
  310.     if (g_ddcaps.dwCKeyCaps & DDCKEYCAPS_DESTOVERLAY)
  311.     {
  312.         // Using a color key will clip the overlay 
  313.         // when the mouse or other windows go on top of us. 
  314.         DWORD dwDDSColor;
  315.  
  316.         // The color key can be any color, but a near black (not exactly) allows
  317.         // the cursor to move around on the window without showing off the
  318.         // color key, and also clips windows with exactly black text.
  319.         CSurface frontSurface; 
  320.         frontSurface.Create( g_pDDSPrimary );
  321.         dwDDSColor = frontSurface.ConvertGDIColor( g_dwBackgroundColor );
  322.         g_OverlayFX.dckDestColorkey.dwColorSpaceLowValue  = dwDDSColor;
  323.         g_OverlayFX.dckDestColorkey.dwColorSpaceHighValue = dwDDSColor;
  324.         g_dwOverlayFlags |= DDOVER_DDFX | DDOVER_KEYDESTOVERRIDE;
  325.     }
  326.     else
  327.     {
  328.         LPDIRECTDRAWCLIPPER pClipper = NULL;
  329.  
  330.         // If not, we'll setup a clipper for the window.  This will fix the
  331.         // problem on a few video cards - but the ones that don't shouldn't
  332.         // care.
  333.         if( FAILED( hr = g_pDD->CreateClipper(0, &pClipper, NULL) ) )
  334.             return hr;
  335.  
  336.         if( FAILED( hr = pClipper->SetHWnd(0, hWnd ) ) )
  337.             return hr;
  338.  
  339.         if( FAILED( hr = g_pDDSPrimary->SetClipper( pClipper ) ) )
  340.             return hr;
  341.  
  342.         SAFE_RELEASE( pClipper );
  343.     }
  344.  
  345.  
  346.     ZeroMemory( &ddsd, sizeof(ddsd) );
  347.     ddsd.dwSize          = sizeof(ddsd);
  348.     ddsd.dwFlags         = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  349.     ddsd.ddsCaps.dwCaps  = DDSCAPS_OFFSCREENPLAIN;
  350.     ddsd.dwWidth         = SPRITE_DIAMETER * 5;
  351.     ddsd.dwHeight        = SPRITE_DIAMETER * 6;
  352.     ddsd.ddpfPixelFormat = ddpfOverlayFormat;  // Use 16 bit RGB 5:6:5 pixel format
  353.  
  354.     // Attempt to create the surface with theses settings
  355.     if( FAILED( hr = g_pDD->CreateSurface( &ddsd, &g_pDDSAnimationSheet, NULL ) ) ) 
  356.         return hr;
  357.  
  358.     CSurface animateSurface; 
  359.     animateSurface.Create( g_pDDSAnimationSheet );
  360.     if( FAILED( hr = animateSurface.DrawBitmap( MAKEINTRESOURCE( IDB_ANIMATE_SHEET ), 
  361.                                                SPRITE_DIAMETER * 5, SPRITE_DIAMETER * 6 ) ) )
  362.         return hr;
  363.  
  364.     return S_OK;
  365. }
  366.  
  367.  
  368.  
  369.  
  370. //-----------------------------------------------------------------------------
  371. // Name: HasOverlaySupport()
  372. // Desc: Returns TRUE if the device supports overlays, FALSE otherwise
  373. //-----------------------------------------------------------------------------
  374. BOOL HasOverlaySupport()
  375. {
  376.     // Get driver capabilities to determine overlay support.
  377.     ZeroMemory( &g_ddcaps, sizeof(g_ddcaps) );
  378.     g_ddcaps.dwSize = sizeof(g_ddcaps);
  379.     g_pDD->GetCaps( &g_ddcaps, NULL );
  380.     
  381.     // Does the driver support overlays in the current mode? 
  382.     // The DirectDraw emulation layer does not support overlays
  383.     // so overlay related APIs will fail without hardware support.  
  384.     if( g_ddcaps.dwCaps & DDCAPS_OVERLAY )
  385.     {
  386.         // Make sure it supports stretching (scaling)
  387.         if ( g_ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH )
  388.             return TRUE;
  389.         else
  390.             return FALSE;
  391.     }
  392.     else
  393.     {
  394.         return FALSE;    
  395.     }
  396. }
  397.  
  398.  
  399.  
  400.  
  401. //-----------------------------------------------------------------------------
  402. // Name: FreeDirectDraw()
  403. // Desc: Release all the DirectDraw objects
  404. //-----------------------------------------------------------------------------
  405. VOID FreeDirectDraw()
  406. {
  407.     SAFE_RELEASE( g_pDDSOverlay ); // g_pDDSOverlayBack will be automatically released here
  408.     SAFE_RELEASE( g_pDDSPrimary );
  409.     SAFE_RELEASE( g_pDDSAnimationSheet ); 
  410.     SAFE_RELEASE( g_pDD );
  411. }
  412.  
  413.  
  414.  
  415.  
  416. //-----------------------------------------------------------------------------
  417. // Name: MainWndProc()
  418. // Desc: The main window procedure
  419. //-----------------------------------------------------------------------------
  420. LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  421. {
  422.     switch (msg)
  423.     {
  424.         case WM_COMMAND:
  425.             switch( LOWORD(wParam) )
  426.             {
  427.                 case IDM_EXIT:
  428.                     // Received key/menu command to exit app
  429.                     PostMessage( hWnd, WM_CLOSE, 0, 0 );
  430.                     return 0L;
  431.             }
  432.             break; // Continue with default processing
  433.  
  434.         case WM_PAINT:
  435.             // Update the screen if we need to refresh. This case occurs 
  436.             // when in windowed mode and the window is behind others.
  437.             // The app will not be active, but it will be visible.
  438.             if( g_pDDSPrimary )
  439.             {
  440.                 // UpdateOverlay is how we put the overlay on the screen.
  441.                 if( g_rcDst.top == g_rcDst.bottom )
  442.                 {
  443.                     g_pDDSOverlay->UpdateOverlay( NULL, g_pDDSPrimary, NULL, 
  444.                                                   DDOVER_HIDE, NULL );
  445.                 }
  446.                 else
  447.                 {
  448.                     g_pDDSOverlay->UpdateOverlay( &g_rcSrc, g_pDDSPrimary,
  449.                                                   &g_rcDst, g_dwOverlayFlags,
  450.                                                   &g_OverlayFX);
  451.                 }
  452.             }
  453.             break; // Continue with default processing to validate the region
  454.  
  455.         case WM_QUERYNEWPALETTE:
  456.             if( g_pDDSPrimary )
  457.             {
  458.                 // If we are in windowed mode with a desktop resolution in 8 bit 
  459.                 // color, then the palette we created during init has changed 
  460.                 // since then.  So get the palette back from the primary 
  461.                 // DirectDraw surface, and set it again so that DirectDraw 
  462.                 // realises the palette, then release it again. 
  463.                 LPDIRECTDRAWPALETTE pDDPal = NULL; 
  464.                 g_pDDSPrimary->GetPalette( &pDDPal );
  465.                 g_pDDSPrimary->SetPalette( pDDPal );
  466.                 SAFE_RELEASE( pDDPal );
  467.             }
  468.             break;
  469.  
  470.         case WM_MOVE:
  471.             // Make sure we're not moving to be minimized - because otherwise
  472.             // our ratio varialbes (g_dwXRatio and g_dwYRatio) will end up
  473.             // being 0, and once we hit CheckBoundries it divides by 0.
  474.             if (!IsIconic(hWnd))
  475.             {
  476.                 POINT p = {0, 0}; // Translation point for the window's client region
  477.  
  478.                 g_rcSrc.left   = 0;
  479.                 g_rcSrc.right  = WINDOW_WIDTH;
  480.                 g_rcSrc.top    = 0;
  481.                 g_rcSrc.bottom = WINDOW_HEIGHT;
  482.  
  483.                 GetClientRect(hWnd, &g_rcDst);
  484.  
  485.                 g_dwXRatio = (g_rcDst.right - g_rcDst.left) * 1000 /
  486.                              (g_rcSrc.right - g_rcSrc.left);
  487.                 g_dwYRatio = (g_rcDst.bottom - g_rcDst.top) * 1000 /
  488.                              (g_rcSrc.bottom - g_rcSrc.top);
  489.  
  490.                 ClientToScreen( hWnd, &p );
  491.                 g_rcDst.left   = p.x;
  492.                 g_rcDst.top    = p.y;
  493.                 g_rcDst.bottom += p.y;
  494.                 g_rcDst.right  += p.x;
  495.                 if( g_pDD )
  496.                     AdjustSizeForHardwareLimits();
  497.             }
  498.             else
  499.             {
  500.                 // Else, hide the overlay... just in case we can't do
  501.                 // destination color keying, this will pull the overlay
  502.                 // off of the screen for the user.
  503.                 if (g_pDDSOverlay && g_pDDSPrimary)
  504.                     g_pDDSOverlay->UpdateOverlay( NULL, g_pDDSPrimary, NULL, 
  505.                                                   DDOVER_HIDE, NULL);
  506.             }
  507.  
  508.             // Check to make sure our window exists before we tell it to
  509.             // repaint. This will fail the first time (while the window is
  510.             // being created).
  511.             if (hWnd)
  512.             {
  513.                 InvalidateRect(hWnd, NULL, FALSE);
  514.                 UpdateWindow(hWnd);
  515.             }
  516.             return 0L;
  517.  
  518.  
  519.         case WM_SIZE:
  520.             // Another check for the minimization action.  This check is
  521.             // quicker though...
  522.             // Check to see if we are losing our window...
  523.             if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )
  524.                 g_bActive = FALSE;
  525.             else
  526.                 g_bActive = TRUE;
  527.  
  528.             if( g_bActive )
  529.             {
  530.                 POINT p = {0, 0}; // Translation point for the window's client region
  531.  
  532.                 GetClientRect(hWnd, &g_rcDst);
  533.                 ClientToScreen(hWnd, &p);
  534.  
  535.                 g_rcDst.left   = p.x;
  536.                 g_rcDst.top    = p.y;
  537.                 g_rcDst.bottom += p.y;
  538.                 g_rcDst.right  += p.x;
  539.  
  540.                 g_rcSrc.left   = 0;
  541.                 g_rcSrc.right  = WINDOW_WIDTH;
  542.                 g_rcSrc.top    = 0;
  543.                 g_rcSrc.bottom = WINDOW_HEIGHT;
  544.  
  545.                 // Here we multiply by 1000 to preserve 3 decimal places in the
  546.                 // division opperation (we picked 1000 to be on the same order
  547.                 // of magnitude as the stretch factor for easier comparisons)
  548.                 g_dwXRatio = (g_rcDst.right - g_rcDst.left) * 1000 /
  549.                              (g_rcSrc.right - g_rcSrc.left);
  550.  
  551.                 g_dwYRatio = (g_rcDst.bottom - g_rcDst.top) * 1000 /
  552.                              (g_rcSrc.bottom - g_rcSrc.top);
  553.  
  554.                 AdjustSizeForHardwareLimits();
  555.             }
  556.             return 0L;
  557.  
  558.  
  559.         case WM_DISPLAYCHANGE:
  560.             // This not only checks for overlay support in the new video mode -
  561.             // but gets the new caps for the new display settings.  That way we
  562.             // have more accurate info about min/max stretch factors, color
  563.             // keying
  564.             if( HasOverlaySupport() == FALSE)
  565.             {
  566.                 MessageBox( hWnd, "You have changed your adapter settings such "
  567.                             " that you no longer support this overlay.", "Overlay", MB_OK );
  568.                 PostMessage( hWnd, WM_CLOSE, 0, 0 );
  569.             }
  570.             return 0L;
  571.         
  572.         case WM_DESTROY:
  573.             // Cleanup and close the app
  574.             FreeDirectDraw();
  575.             PostQuitMessage( 0 );
  576.             return 0L;
  577.     }
  578.  
  579.     return DefWindowProc(hWnd, msg, wParam, lParam);
  580. }
  581.  
  582.  
  583.  
  584.  
  585. //-----------------------------------------------------------------------------
  586. // Name: AdjustSizeForHardwareLimits()
  587. // Desc: Checks and corrects all boundries for alignment and stretching
  588. //-----------------------------------------------------------------------------
  589. VOID AdjustSizeForHardwareLimits()
  590. {
  591.     // Setup effects structure
  592.     // Make sure the coordinates fulfill the stretching requirements.  Often
  593.     // the hardware will require a certain ammount of stretching to do
  594.     // overlays. This stretch factor is held in dwMinOverlayStretch as the
  595.     // stretch factor multiplied by 1000 (to keep an accuracy of 3 decimal
  596.     // places).
  597.     if( (g_ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) && 
  598.         (g_ddcaps.dwMinOverlayStretch)            && 
  599.         (g_dwXRatio < g_ddcaps.dwMinOverlayStretch) )
  600.     {
  601.         // Window is too small
  602.         g_rcDst.right = 2 * GetSystemMetrics(SM_CXSIZEFRAME) + g_rcDst.left + (WINDOW_WIDTH
  603.                                  * (g_ddcaps.dwMinOverlayStretch + 1)) / 1000;
  604.     }
  605.  
  606.     if( (g_ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) && 
  607.         (g_ddcaps.dwMaxOverlayStretch)            && 
  608.         (g_dwXRatio > g_ddcaps.dwMaxOverlayStretch) )
  609.     {
  610.         // Window is too large
  611.         g_rcDst.right = 2 * GetSystemMetrics(SM_CXSIZEFRAME) + g_rcDst.left + (WINDOW_HEIGHT
  612.                                * (g_ddcaps.dwMaxOverlayStretch + 999)) / 1000;
  613.     }
  614.  
  615.     // Recalculate the ratio's for the upcoming calculations
  616.     g_dwXRatio = (g_rcDst.right  - g_rcDst.left) * 1000 / (g_rcSrc.right  - g_rcSrc.left);
  617.     g_dwYRatio = (g_rcDst.bottom - g_rcDst.top)  * 1000 / (g_rcSrc.bottom - g_rcSrc.top);
  618.  
  619.     // Check to make sure we're within the screen's boundries, if not then fix
  620.     // the problem by adjusting the source rectangle which we draw from.
  621.     if (g_rcDst.left < 0)
  622.     {
  623.         g_rcSrc.left = -g_rcDst.left * 1000 / g_dwXRatio;
  624.         g_rcDst.left = 0;
  625.     }
  626.  
  627.     if (g_rcDst.right > GetSystemMetrics(SM_CXSCREEN))
  628.     {
  629.         g_rcSrc.right = WINDOW_WIDTH - ((g_rcDst.right - GetSystemMetrics(SM_CXSCREEN)) *
  630.                                 1000 / g_dwXRatio);
  631.         g_rcDst.right = GetSystemMetrics(SM_CXSCREEN);
  632.     }
  633.  
  634.     if (g_rcDst.bottom > GetSystemMetrics(SM_CYSCREEN))
  635.     {
  636.         g_rcSrc.bottom = WINDOW_HEIGHT - ((g_rcDst.bottom - GetSystemMetrics(SM_CYSCREEN))
  637.                                  * 1000 / g_dwYRatio);
  638.         g_rcDst.bottom = GetSystemMetrics(SM_CYSCREEN);
  639.     }
  640.  
  641.     if (g_rcDst.top < 0)
  642.     {
  643.         g_rcSrc.top = -g_rcDst.top * 1000 / g_dwYRatio;
  644.         g_rcDst.top = 0;
  645.     }
  646.  
  647.     // Make sure the coordinates fulfill the alignment requirements
  648.     // these expressions (x & -y) just do alignment by dropping low order bits...
  649.     // so to round up, we add first, then truncate.
  650.     if( (g_ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC) && 
  651.         (g_ddcaps.dwAlignBoundarySrc) )
  652.     {
  653.         g_rcSrc.left = (g_rcSrc.left + g_ddcaps.dwAlignBoundarySrc / 2) & 
  654.                         -(signed) (g_ddcaps.dwAlignBoundarySrc);
  655.     }
  656.  
  657.     if( (g_ddcaps.dwCaps & DDCAPS_ALIGNSIZESRC) && 
  658.         (g_ddcaps.dwAlignSizeSrc) )
  659.     {
  660.         g_rcSrc.right = g_rcSrc.left + (g_rcSrc.right - g_rcSrc.left + g_ddcaps.dwAlignSizeSrc / 2) & 
  661.                          -(signed) (g_ddcaps.dwAlignSizeSrc);
  662.     }
  663.  
  664.     if( (g_ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST) && 
  665.         (g_ddcaps.dwAlignBoundaryDest) )
  666.     {
  667.         g_rcDst.left = ( g_rcDst.left + g_ddcaps.dwAlignBoundaryDest / 2 ) & 
  668.                        -(signed) (g_ddcaps.dwAlignBoundaryDest);
  669.     }
  670.  
  671.     if( (g_ddcaps.dwCaps & DDCAPS_ALIGNSIZEDEST) && 
  672.         (g_ddcaps.dwAlignSizeDest) )
  673.     {
  674.         g_rcDst.right = g_rcDst.left + (g_rcDst.right - g_rcDst.left) & 
  675.                         -(signed) (g_ddcaps.dwAlignSizeDest);
  676.     }
  677. }
  678.  
  679.  
  680.  
  681.  
  682. //-----------------------------------------------------------------------------
  683. // Name: ProcessNextFrame()
  684. // Desc: Move the sprites, blt them to the back buffer, then 
  685. //       flip or blt the back buffer to the primary buffer
  686. //-----------------------------------------------------------------------------
  687. HRESULT ProcessNextFrame( HWND hWnd )
  688. {
  689.     static  s_dwFrameSkip = 0; 
  690.     HRESULT hr;
  691.  
  692.     // Only advance the frame animation number every 5th frame
  693.     s_dwFrameSkip++;
  694.     s_dwFrameSkip %= 5;
  695.  
  696.     if( s_dwFrameSkip == 0 )
  697.     {
  698.         g_dwFrame++;
  699.         g_dwFrame %= NUM_FRAMES;
  700.     }
  701.  
  702.     // Check the cooperative level before rendering
  703.     if( FAILED( hr = g_pDD->TestCooperativeLevel() ) )
  704.     {
  705.         switch( hr )
  706.         {
  707.             case DDERR_EXCLUSIVEMODEALREADYSET:
  708.                 // Do nothing because some other app has exclusive mode
  709.                 Sleep(10);
  710.                 return S_OK;
  711.  
  712.             case DDERR_WRONGMODE:
  713.                 // The display mode changed on us. Update the
  714.                 // DirectDraw surfaces accordingly
  715.                 return CreateDirectDrawSurfaces( hWnd );
  716.         }
  717.         return hr;
  718.     }
  719.  
  720.     // Display the sprites on the screen
  721.     if( FAILED( hr = DisplayFrame() ) )
  722.     {
  723.         if( hr != DDERR_SURFACELOST )
  724.             return hr;
  725.  
  726.         // The surfaces were lost so restore them 
  727.         RestoreSurfaces();
  728.     }
  729.  
  730.     return S_OK;
  731. }
  732.  
  733.  
  734.  
  735.  
  736. //-----------------------------------------------------------------------------
  737. // Name: DisplayFrame()
  738. // Desc: Blts a the sprites to the back buffer, then flips the 
  739. //       back buffer onto the primary buffer.
  740. //-----------------------------------------------------------------------------
  741. HRESULT DisplayFrame()
  742. {
  743.     HRESULT hr;
  744.     RECT    rcSrc;
  745.  
  746.     rcSrc.left   = (g_dwFrame % 5) * SPRITE_DIAMETER;
  747.     rcSrc.top    = (g_dwFrame / 5) * SPRITE_DIAMETER;
  748.     rcSrc.right  = rcSrc.left + SPRITE_DIAMETER;
  749.     rcSrc.bottom = rcSrc.top  + SPRITE_DIAMETER;
  750.  
  751.     g_pDDSOverlayBack->Blt( NULL, g_pDDSAnimationSheet, 
  752.                             &rcSrc, DDBLT_WAIT, NULL );
  753.  
  754.     if( FAILED( hr = g_pDDSOverlay->Flip( NULL, DDFLIP_WAIT ) ) )
  755.         return hr;
  756.  
  757.     return S_OK;
  758. }
  759.  
  760.  
  761.  
  762.  
  763.  
  764. //-----------------------------------------------------------------------------
  765. // Name: RestoreSurfaces()
  766. // Desc: Restore all the surfaces, and redraw the sprite surfaces.
  767. //-----------------------------------------------------------------------------
  768. HRESULT RestoreSurfaces()
  769. {
  770.     HRESULT hr;
  771.  
  772.     if( FAILED( hr = g_pDD->RestoreAllSurfaces() ) )
  773.         return hr;
  774.  
  775.     // No need to re-create the surface, just re-draw it.
  776.     CSurface animateSurface; 
  777.     animateSurface.Create( g_pDDSAnimationSheet );
  778.     if( FAILED( hr = animateSurface.DrawBitmap( MAKEINTRESOURCE( IDB_ANIMATE_SHEET ),
  779.                                                SPRITE_DIAMETER * 5, SPRITE_DIAMETER * 6 ) ) )
  780.         return hr;
  781.  
  782.     return S_OK;
  783. }
  784.  
  785.  
  786.  
  787.